﻿package fpc.changers;
import haxe.unit.TestCase;

class AChangerAdapterTest extends TestCase
{
	public function new() 
	{
		super();
	}
	
	var _floatChanger:Changer<Float>;
	
	var _intChanger:Changer<Int>;
	
	var _stringChanger:Changer<String>;
	
	var _intValue:Int;
	
	function onIntChange(value:Int)
	{
		_intChanger.value = value;
		_intValue = value;
	}
	
	var _floatValue:Float;
	
	function onFloatChange(value:Float)
	{
		_floatChanger.value = value;
		_floatValue = value;
	}
	
	var _stringValue:String;
	
	function onStringChange(value:String)
	{
		_stringChanger.value = value;
		_stringValue = value;
	}
	
	// FLOAT TO INT
	
	public function testFloatToIntConversion()
	{
		_floatChanger = new Changer<Float>(onFloatChange);
		_intChanger = new Changer<Int>(onIntChange);
		
		_intChanger.linkTo(new TestIntFloatAdapter(_floatChanger));
		
		_intChanger.value = 10;
		assertEquals(10, _intChanger.value);
		assertEquals(10., _floatChanger.value);
		assertEquals(10, _intValue);
		assertEquals(10., _floatValue);
		
		onFloatChange(50);
		assertEquals(50, _intChanger.value);
		assertEquals(50., _floatChanger.value);
		assertEquals(50, _intValue);
		assertEquals(50., _floatValue);
		
		_intChanger.value = 200;
		assertEquals(200, _intChanger.value);
		assertEquals(200., _floatChanger.value);
		assertEquals(200, _intValue);
		assertEquals(200., _floatValue);
		
		_floatChanger.value = 30;
		assertEquals(30, _intChanger.value);
		assertEquals(30., _floatChanger.value);
		assertEquals(30, _intValue);
		assertEquals(30., _floatValue);
	}
	
	public function testFloatToIntConversionScope()
	{
		_floatChanger = new Changer<Float>(onFloatChange);
		_intChanger = new Changer<Int>(onIntChange);
		
		_intChanger.linkTo(new TestIntFloatAdapter(_floatChanger));
		
		_floatChanger.value = 20;
		assertEquals(20, _intChanger.value);
		assertEquals(20., _floatChanger.value);
		assertEquals(20, _intValue);
		assertEquals(20., _floatValue);
		
		_floatChanger.value = 20.01;
		assertEquals(20, _intChanger.value);
		assertEquals(20.01, _floatChanger.value);
		assertEquals(20, _intValue);
		assertEquals(20.01, _floatValue);
		
		onFloatChange(30.1);
		assertEquals(30, _intChanger.value);
		assertEquals(30.1, _floatChanger.value);
		assertEquals(30, _intValue);
		assertEquals(30.1, _floatValue);
		
		onIntChange(30);
		assertEquals(30, _intChanger.value);
		assertEquals(30., _floatChanger.value);
		assertEquals(30, _intValue);
		assertEquals(30., _floatValue);
		
		_intChanger.value = 1000;
		assertEquals(1000, _intChanger.value);
		assertEquals(1000., _floatChanger.value);
		assertEquals(1000, _intValue);
		assertEquals(1000., _floatValue);
	}
	
	// STRING TO FLOAT
	
	public function testStringToFloatConversion()
	{
		_floatChanger = new Changer<Float>(onFloatChange);
		_stringChanger = new Changer<String>(onStringChange);
		
		_floatChanger.linkTo(new FloatStringAdapter(_stringChanger));
		
		onFloatChange(10.1);
		assertEquals(10.1, _floatValue);
		assertEquals('10.1', _stringValue);
		
		onStringChange('20.7');
		assertEquals(20.7, _floatValue);
	}
	
	public function testStringToFloatScope()
	{
		_floatChanger = new Changer<Float>(onFloatChange);
		_stringChanger = new Changer<String>(onStringChange);
		
		_floatChanger.linkTo(new FloatStringAdapter(_stringChanger));
		
		onStringChange('30.234');
		assertEquals(30.234, _floatValue);
		assertEquals(30.234, _floatChanger.value);
		assertEquals('30.234', _stringValue);
		assertEquals('30.234', _stringChanger.value);
		
		onStringChange('skl234s');
		assertEquals(30.234, _floatValue);
		assertEquals(30.234, _floatChanger.value);
		assertEquals('skl234s', _stringValue);
		assertEquals('skl234s', _stringChanger.value);
		
		onStringChange('100.02');
		assertEquals(100.02, _floatValue);
		assertEquals(100.02, _floatChanger.value);
		assertEquals('100.02', _stringValue);
		assertEquals('100.02', _stringChanger.value);
		
		_floatChanger.value = Math.NaN;
		assertTrue(Math.isNaN(_floatValue));
		assertTrue(Math.isNaN(_floatChanger.value));
		assertEquals('100.02', _stringValue);
		assertEquals('100.02', _stringChanger.value);
		
		onFloatChange(100);
		assertEquals(100., _floatValue);
		assertEquals(100., _floatChanger.value);
		assertEquals('100', _stringValue);
		assertEquals('100', _stringChanger.value);
	}
}

private class TestIntFloatAdapter extends AChangerAdapter<Int, Float>
{
	override function fromAdapted(value:Int, adaptedValue:Float):Int
	{
		value = Std.int(adaptedValue);
		return value;
	}
	
	override function toAdapted(value:Int, adaptedValue:Float):Float
	{
		adaptedValue = value;
		return adaptedValue;
	}
}

private class TestFloatStringAdapter extends AChangerAdapter<Float, String>
{
	override function fromAdapted(value:Float, adaptedValue:String):Float
	{
		var newValue = Std.parseFloat(adaptedValue);
		if (Math.isNaN(newValue))
		{
			return value;
		}
		return newValue;
	}
	
	override function toAdapted(value:Float, adaptedValue:String):String
	{
		if (Math.isNaN(value))
		{
			return adaptedValue;
		}
		return Std.string(value);
	}
}